<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  canvas {
    display: block;
    margin: 0 auto;
    border: 2px solid #aaa;
  }
</style>
<body>
  <canvas id="canvas" height="500px" width="500px">
    您的浏览器版本过低，请升级浏览器或者使用谷歌浏览器打开！
  </canvas>
  <script>
     /** @type {HTMLCanvasElement} */
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    class Ball {
      constructor() {
        this.x = Math.floor(Math.random() * 500) + 1;
        this.y = Math.floor(Math.random() * 500) + 1;
        this.r = Math.ceil(Math.random() * 15) + 5;
        this.xSpeed = Math.ceil(Math.random() * 1) + 1;
        this.ySpeed = Math.ceil(Math.random() * 1) + 2;
      }

      // 运动
      run() {

        /**
         * 在小球碰到边缘时，速度去相反即可
         */
        if (this.x - this.r <= 0 || this.x + this.r >= w ) {
          this.xSpeed = -this.xSpeed;
        }
        this.x = this.x - this.xSpeed;

        if (this.y - this.r <= 0 || this.y + this.r >= h ) {
          this.ySpeed = -this.ySpeed;
        }
        this.y = this.y - this.ySpeed;
        // 水平移动
        drawCircle(this.x, this.y, this.r);
      }
    }

    // 画布宽高
    var w=h=500;

    setInterval(() => {
      // 清除画布
      ctx.clearRect(0, 0, w, h);


      for (let i = 0; i < 100; i++) {
        const ball = new Ball();
        ball.run();
      }
    }, 10);

    function drawCircle(x, y, r) {
      ctx.beginPath();
      ctx.arc(x, y, r, 0, Math.PI * 2);
      ctx.fillStyle = '#' + parseInt(Math.random() * 0xffffff).toString(16);
      ctx.fill();
    }
</script>
  </script>
</body>
</html>